<template>
  <NvGrid
    class="nv-form-grid"
    :cols="24"
    :x-gap="props.option.xGap ?? props.mode === 'view' ? 1 : 12"
    :y-gap="props.option.yGap ?? props.mode === 'view' ? 2 : 0"
    :collapsed="collapsed"
    :collapsed-rows="collapsedRow"
    item-responsive
    item-span-zero-directive="show"
    suffix-align="left"
    suffix-fill
    @responsive-rows="rows => responsiveRows = rows"
    @responsive-cols="cols => responsiveCols = cols"
    @suffix-filled="filled => suffixFilled = filled"
  >
    <template v-for="([field, _option], index) in sortedFields" :key="field">
      <NGridItem
        v-if="resolveDynamicValue(_option.formVisible, formData) !== false"
        :style="{ gridRow: `span ${_option.verticalSpan ?? 1}` }"
        :span="computeSpan(_option.span ?? 24, index, _option.suffix)"
        :offset="_option.offset"
        :suffix="_option.suffix"
        #="{ overflow } = {}"
      >
        <FormItem
          :form="form"
          :field="field"
          :option="_option"
          :mode="props.mode"
          :feedback-class="props.option.feedbackClass"
          :feedback-style="props.option.feedbackStyle"
          :label-style="props.option.labelStyle"
        >
          <template #default="{ component, renderView, vModel, fieldProps, fieldSlots, dictData, loading }">
            <slot
              :name="`${field}_${props.mode === 'view' ? 'view' : 'form'}`"
              :row-data="{ ...formData }"
              :render-view="renderView"
              :dict-data="dictData"
              :loading="loading"
              :mode="props.mode"
              :grid-overflow="overflow"
              :grid-responsive-rows="responsiveRows"
              :grid-responsive-cols="responsiveCols"
              :grid-suffix-filled="suffixFilled"
            >
              <component
                :is="component"
                :[vModel]="get(formData, field)"
                :[`onUpdate:${vModel}`]="(val: any) => set(formData, field, val)"
                :dict-data="dictData"
                :loading="loading"
                :clearable="_option.clearable"
                :placeholder="_option.placeholder"
                v-bind="fieldProps"
                :readonly="resolveDynamicValue(_option?.readonly, formData)"
                :disabled="resolveDynamicValue(_option?.disabled, formData)"
                :mode="props.mode"
              >
                <template v-for="(slot, name) in fieldSlots" :key="name" #[name]="slotProps">
                  <component :is="slot" v-bind="slotProps" />
                </template>
              </component>
            </slot>
          </template>
        </FormItem>
      </NGridItem>
    </template>
  </NvGrid>
</template>

<script setup lang="ts">
import type { NvFormItemOption, NvFormMode, NvFormOption } from '@/form/types'
import type { RowData } from '@/types'
import { get, set } from 'lodash-es'
import { NGridItem } from 'naive-ui'
import { computed, ref } from 'vue'
import { NvGrid } from '@/components'
import { resolveDynamicValue, sortCompare } from '@/utils'
import { useCollapse } from '@/utils/collapse'
import FormItem from './FormItem.vue'

interface Props {
  form: RowData
  fields: Record<string, NvFormItemOption>
  option: NvFormOption
  mode?: NvFormMode
}
const props = defineProps<Props>()

const formData = defineModel<RowData>('form', { required: true })

const { collapsed = ref(false), collapsedRow, collapsedNum } = useCollapse()
function computeSpan(span: string | number, index: number, suffix?: boolean) {
  if (!collapsed.value)
    return span

  if (typeof collapsedNum === 'number') {
    if (index >= collapsedNum && !suffix)
      return 0
  }
  return span
}

const sortedFields = computed<([string, NvFormItemOption])[]>(() => {
  return Object.entries(props.fields)
    .sort(([, a], [, b]) => sortCompare(a.formOrder, b.formOrder))
})

const responsiveRows = ref(0)
const responsiveCols = ref(0)
const suffixFilled = ref(false)
</script>

<style lang="scss">
.nv-form-grid {
  flex: 1;
}
</style>
